#ifndef TLS_SOCKET_H_
#define TLS_SOCKET_H_

#include <cstdint>
#include <memory>
#include <string>
#include <openssl/ossl_typ.h>
#include <openssl/ssl.h>
#include <pthread.h>

class Description;
class TlsSocketOperate
{
public:
    struct TlsTcpOption
    {
        std::string m_host_name;
        std::string m_public_crt_file;
        std::string m_private_key_file;
        std::string m_ca_file;
        std::string m_ssl_key_log_file;
    };
    enum EmOperateType
    {
        EmOperateTls  = 0,  // client
        EmOperateDTls = 1,  // client
        EmOperateTlsServer, //
        EmOperateDTlsServer
    };
    typedef TlsTcpOption TlsOption;
public:
    explicit TlsSocketOperate(std::shared_ptr<Description> description, int operate_type);
    ~TlsSocketOperate();
    int  Connection();
    int  Connection(const TlsOption& option);
    int  ServerConnection();
    int  ServerConnection(const TlsOption & option);
    int  HandShake() const;
    void Close();
    int  Write(const uint8_t * data, int length) const;
    int  Read(uint8_t * data, int length) const;
private:
    static int ConfigSSL(BIO * ssl, const TlsSocketOperate::TlsOption & option);
    static BIO * CreateSSL(int operate_type, const std::shared_ptr<Description>& description);
    static void  WriteSSLLogFile(const SSL * ssl, const char * line);
private:
    std::shared_ptr<Description> m_description;
    BIO *                        m_bio_ssl;
    int                          m_operate_type;
private:
    static void           InitTlsSocket();
    static SSL_CTX *      s_m_client_ssl_ctx;
    static SSL_CTX *      s_m_server_ssl_ctx;
    static SSL_CTX *      s_m_udp_client_ssl_ctx;
    static SSL_CTX *      s_m_udp_server_ssl_ctx;
    static std::string    s_m_ssl_log_file;
    static pthread_once_t s_m_once;
};

#endif
